// MSR.h - model specific registers.

#ifndef __ARCH_X86_MSR_H__
#define __ARCH_X86_MSR_H__

#include <cstdint>

namespace Kernel
{
	namespace MSR
	{
		enum MsrIndex : uint32_t
		{
			MC_ADDR                    = 0x00000000,
			MC_TYPE                    = 0x00000001,
			MONITOR_FILTER_SIZE        = 0x00000006,
			TIME_STAMP_COUNTER         = 0x00000010,
			PLATFORM_ID                = 0x00000017,
			APIC_BASE                  = 0x0000001b,
			EBL_CR_POWERON             = 0x0000002a,
			FEATURE_CONTROL            = 0x0000003a,
			LASTBRANCH_0_FROM_IP       = 0x00000040,
			LASTBRANCH_1_FROM_IP       = 0x00000041,
			LASTBRANCH_2_FROM_IP       = 0x00000042,
			LASTBRANCH_3_FROM_IP       = 0x00000043,
			LASTBRANCH_0_TO_LIP        = 0x00000060,
			LASTBRANCH_1_TO_LIP        = 0x00000061,
			LASTBRANCH_2_TO_LIP        = 0x00000062,
			LASTBRANCH_3_TO_LIP        = 0x00000063,
			BIOS_UPDT_TRIG             = 0x00000079,
			BIOS_SIGN_ID               = 0x0000008b,
			SMM_MONITOR_CTL            = 0x0000009b,
			PMC0                       = 0x000000c1,
			PMC1                       = 0x000000c2,
			PMC2                       = 0x000000c3,
			PMC3                       = 0x000000c4,
			FSB_FREQ                   = 0x000000cd,
			PLATFORM_INFO              = 0x000000ce,
			MPERF                      = 0x000000e7,
			APERF                      = 0x000000e8,
			MTRRCAP                    = 0x000000fe,
			BBL_CR_CTL3                = 0x0000011e,
			SYSENTER_CS                = 0x00000174,
			SYSENTER_ESP               = 0x00000175,
			SYSENTER_EIP               = 0x00000176,
			MCG_CAP                    = 0x00000179,
			MCG_STATUS                 = 0x0000017a,
			MCG_CTL                    = 0x0000017b,
			PERFEVTSEL0                = 0x00000186,
			PERFEVTSEL1                = 0x00000187,
			PERFEVTSEL2                = 0x00000188,
			PERFEVTSEL3                = 0x00000189,
			PERF_STATUS                = 0x00000198,
			PERF_CTL                   = 0x00000199,
			CLOCK_MODULATION           = 0x0000019a,
			THERM_INTERRUPT            = 0x0000019b,
			THERM_STATUS               = 0x0000019c,
			THERM2_CTL                 = 0x0000019d,
			MISC_ENABLE                = 0x000001a0,
			TEMPERATURE_TARGET         = 0x000001a2,
			OFFCORE_RSP0               = 0x000001a6,
			TURBO_RATIO_LIMIT          = 0x000001ad,
			LBR_SELECT                 = 0x000001c8,
			LASTBRANCH_TOS             = 0x000001c9,
			DEBUG_CTL                  = 0x000001d9,
			LER_FROM_LIP               = 0x000001dd,
			LER_TO_LIP                 = 0x000001de,
			PLATFORM_DCA_CAP           = 0x000001f8,
			MTRR_PHYSBASE0             = 0x00000200,
			MTRR_PHYSMASK0             = 0x00000201,
			MTRR_PHYSBASE1             = 0x00000202,
			MTRR_PHYSMASK1             = 0x00000203,
			MTRR_PHYSBASE2             = 0x00000204,
			MTRR_PHYSMASK2             = 0x00000205,
			MTRR_PHYSBASE3             = 0x00000206,
			MTRR_PHYSMASK3             = 0x00000207,
			MTRR_PHYSBASE4             = 0x00000208,
			MTRR_PHYSMASK4             = 0x00000209,
			MTRR_PHYSBASE5             = 0x0000020a,
			MTRR_PHYSMASK5             = 0x0000020b,
			MTRR_PHYSBASE6             = 0x0000020c,
			MTRR_PHYSMASK6             = 0x0000020d,
			MTRR_PHYSBASE7             = 0x0000020e,
			MTRR_PHYSMASK7             = 0x0000020f,
			MTRR_FIX64K_00000          = 0x00000250,
			MTRR_FIX16K_80000          = 0x00000258,
			MTRR_FIX16K_A0000          = 0x00000259,
			MTRR_FIX4K_C0000           = 0x00000268,
			MTRR_FIX4K_C8000           = 0x00000269,
			MTRR_FIX4K_D0000           = 0x0000026a,
			MTRR_FIX4K_D8000           = 0x0000026b,
			MTRR_FIX4K_E0000           = 0x0000026c,
			MTRR_FIX4K_E8000           = 0x0000026d,
			MTRR_FIX4K_F0000           = 0x0000026e,
			MTRR_FIX4K_F8000           = 0x0000026f,
			CR_PAT                     = 0x00000277,
			MC0_CTL2                   = 0x00000280,
			MC1_CTL2                   = 0x00000281,
			MC2_CTL2                   = 0x00000282,
			MC3_CTL2                   = 0x00000283,
			MC4_CTL2                   = 0x00000284,
			MC5_CTL2                   = 0x00000285,
			MC6_CTL2                   = 0x00000286,
			MC7_CTL2                   = 0x00000287,
			MC8_CTL2                   = 0x00000288,
			MTRR_DEF_TYPE              = 0x000002ff,
			FIXED_CTR0                 = 0x00000309,
			FIXED_CTR1                 = 0x0000030a,
			FIXED_CTR2                 = 0x0000030b,
			PERF_CAPABILITIES          = 0x00000345,
			FIXED_CTR_CTL              = 0x0000038d,
			PERF_GLOBAL_STATUS         = 0x0000038e,
			PERF_GLOBAL_CTL            = 0x0000038f,
			PERF_GLOBAL_OVF_CTL        = 0x00000390,
			UNCORE_PERF_GLOBAL_CTL     = 0x00000391,
			UNCORE_PERF_GLOBAL_STATUS  = 0x00000392,
			UNCORE_PERF_GLOBAL_OVF_CTL = 0x00000393,
			UNCORE_FIXED_CTR0          = 0x00000394,
			UNCORE_FIXED_CTR_CTL       = 0x00000395,
			UNCORE_ADDR_OPCODE_MATCH   = 0x00000396,
			UNCORE_PERFEVTSEL0         = 0x000003b0,
			UNCORE_PERFEVTSEL1         = 0x000003b1,
			UNCORE_PERFEVTSEL2         = 0x000003b2,
			UNCORE_PERFEVTSEL3         = 0x000003b3,
			UNCORE_PERFEVTSEL4         = 0x000003b4,
			UNCORE_PERFEVTSEL5         = 0x000003b5,
			UNCORE_PERFEVTSEL6         = 0x000003b6,
			UNCORE_PERFEVTSEL7         = 0x000003b7,
			UNCORE_PMC0                = 0x000003c0,
			UNCORE_PMC1                = 0x000003c1,
			UNCORE_PMC2                = 0x000003c2,
			UNCORE_PMC3                = 0x000003c3,
			UNCORE_PMC4                = 0x000003c4,
			UNCORE_PMC5                = 0x000003c5,
			UNCORE_PMC6                = 0x000003c6,
			UNCORE_PMC7                = 0x000003c7,
			PEBS_ENABLE                = 0x000003f1,
			PEBS_LD_LAT                = 0x000003f6,
			PKG_C3_RESIDENCY           = 0x000003f8,
			PKG_C6_RESIDENCY           = 0x000003f9,
			PKG_C7_RESIDENCY           = 0x000003fa,
			CORE_C3_RESIDENCY          = 0x000003fc,
			CORE_C6_RESIDENCY          = 0x000003fd,
			MC0_CTL                    = 0x00000400,
			MC0_STATUS                 = 0x00000401,
			MC0_ADDR                   = 0x00000402,
			MC0_MISC                   = 0x00000403,
			MC1_CTL                    = 0x00000404,
			MC1_STATUS                 = 0x00000405,
			MC1_ADDR                   = 0x00000406,
			MC1_MISC                   = 0x00000407,
			MC2_CTL                    = 0x00000408,
			MC2_STATUS                 = 0x00000409,
			MC2_ADDR                   = 0x0000040a,
			MC2_MISC                   = 0x0000040b,
			MC3_CTL                    = 0x0000040c,
			MC3_STATUS                 = 0x0000040d,
			MC3_ADDR                   = 0x0000040e,
			MC3_MISC                   = 0x0000040f,
			MC4_CTL                    = 0x00000410,
			MC4_STATUS                 = 0x00000411,
			MC4_ADDR                   = 0x00000412,
			MC4_MISC                   = 0x00000413,
			MC5_CTL                    = 0x00000414,
			MC5_STATUS                 = 0x00000415,
			MC5_ADDR                   = 0x00000416,
			MC5_MISC                   = 0x00000417,
			MC6_STATUS                 = 0x00000419,
			MC7_STATUS                 = 0x0000041d,
			MC8_STATUS                 = 0x00000421,
			VMX_BASIC                  = 0x00000480,
			VMX_PINBASED_CTLS          = 0x00000481,
			VMX_PROCBASED_CTLS         = 0x00000482,
			VMX_EXIT_CTLS              = 0x00000483,
			VMX_ENTRY_CTLS             = 0x00000484,
			VMX_MISC_CTLS              = 0x00000485,
			VMX_CR0_FIXED0             = 0x00000486,
			VMX_CR0_FIXED1             = 0x00000487,
			VMX_CR4_FIXED0             = 0x00000488,
			VMX_CR4_FIXED1             = 0x00000489,
			VMX_VMCS_ENUM              = 0x0000048a,
			VMX_PROCBASED_CTLS2        = 0x0000048b,
			VMX_EPT_VPID_CAP           = 0x0000048c,
			VMX_TRUE_PINBASES_CTLS     = 0x0000048d,
			VMX_TRUE_PROCBASED_CTLS    = 0x0000048e,
			VMX_TRUE_EXIT_CTLS         = 0x0000048f,
			VMX_TRUE_ENTRY_CTLS        = 0x00000490,
			DS_AREA                    = 0x00000600,
			EXT_XAPICID                = 0x00000802,
			EXT_XAPIC_VERSION          = 0x00000803,
			EXT_XAPIC_TPR              = 0x00000808,
			EXT_XAPIC_PPR              = 0x0000080a,
			EXT_XAPIC_EOI              = 0x0000080b,
			EXT_XAPIC_LDR              = 0x0000080d,
			EXT_XAPIC_SIVR             = 0x0000080f,
			EXT_XAPIC_ISR0             = 0x00000810,
			EXT_XAPIC_ISR1             = 0x00000811,
			EXT_XAPIC_ISR2             = 0x00000812,
			EXT_XAPIC_ISR3             = 0x00000813,
			EXT_XAPIC_ISR4             = 0x00000814,
			EXT_XAPIC_ISR5             = 0x00000815,
			EXT_XAPIC_ISR6             = 0x00000816,
			EXT_XAPIC_ISR7             = 0x00000817,
			EXT_XAPIC_TMR0             = 0x00000818,
			EXT_XAPIC_TMR1             = 0x00000819,
			EXT_XAPIC_TMR2             = 0x0000081a,
			EXT_XAPIC_TMR3             = 0x0000081b,
			EXT_XAPIC_TMR4             = 0x0000081c,
			EXT_XAPIC_TMR5             = 0x0000081d,
			EXT_XAPIC_TMR6             = 0x0000081e,
			EXT_XAPIC_TMR7             = 0x0000081f,
			EXT_XAPIC_IRR0             = 0x00000820,
			EXT_XAPIC_IRR1             = 0x00000821,
			EXT_XAPIC_IRR2             = 0x00000822,
			EXT_XAPIC_IRR3             = 0x00000823,
			EXT_XAPIC_IRR4             = 0x00000824,
			EXT_XAPIC_IRR5             = 0x00000825,
			EXT_XAPIC_IRR6             = 0x00000826,
			EXT_XAPIC_IRR7             = 0x00000827,
			EXT_XAPIC_ESR              = 0x00000828,
			EXT_XAPIC_CMCI             = 0x0000082f,
			EXT_XAPIC_ICR              = 0x00000830,
			EXT_XAPIC_LVT_TIMER        = 0x00000832,
			EXT_XAPIC_LVT_THERMAL      = 0x00000833,
			EXT_XAPIC_LVT_PMI          = 0x00000834,
			EXT_XAPIC_LVT_LINT0        = 0x00000835,
			EXT_XAPIC_LVT_LINT1        = 0x00000836,
			EXT_XAPIC_LVT_ERROR        = 0x00000837,
			EXT_XAPIC_INIT_COUNT       = 0x00000838,
			EXT_XAPIC_CUR_COUNT        = 0x00000839,
			EXT_XAPIC_DIV_CONF         = 0x0000083e,
			EXT_XAPIC_SELF_IPI         = 0x0000083f,
			EMON_L3_CTR_CTL0           = 0x000107cc,
			EMON_L3_CTR_CTL1           = 0x000107cd,
			EMON_L3_CTR_CTL2           = 0x000107ce,
			EMON_L3_CTR_CTL3           = 0x000107cf,
			EMON_L3_CTR_CTL4           = 0x000107d0,
			EMON_L3_CTR_CTL5           = 0x000107d1,
			EMON_L3_CTR_CTL6           = 0x000107d2,
			EMON_L3_CTR_CTL7           = 0x000107d3,
			EMON_L3_GL_CTL             = 0x000107d8,
			EFER                       = 0xc0000080,
			STAR                       = 0xc0000081,
			LSTAR                      = 0xc0000082,
			FMASK                      = 0xc0000083,
			FS_BASE                    = 0xc0000100,
			GS_BASE                    = 0xc0000101,
			KERNEL_GS_BASE             = 0xc0000102,
			TSC_AUX                    = 0xc0000103
		};

		inline uint64_t Read(uint32_t msr)
		{
			uint32_t high, low;

			asm volatile ("rdmsr" : "=a"(low), "=d"(high) : "c"(msr));
			return((((uint64_t)high) << 32) + (uint64_t)low);
		}

		inline void Write(uint32_t msr, uint64_t value)
		{
			asm volatile ("wrmsr" : : "a"((uint32_t)value), "d"((uint32_t)(value >> 32)), "c"(msr));
		}
	}
}

#endif
